<!-- +----------------------------------------------------------------------
| 麦沃德科技赋能开发者，助力中小企业发展 
+----------------------------------------------------------------------
| Copyright (c) 2017～2024  www.wdadmin.cn    All rights reserved.
+----------------------------------------------------------------------
| 沃德代驾系统并不是自由软件，不加密，并不代表开源，未经许可不可自由转售和商用
+----------------------------------------------------------------------
| Author: MY WORLD Team <bd@maiwd.cn>   www.wdadmin.cn
+----------------------------------------------------------------------
| 抢单 开发者: 麦沃德科技-半夏
+---------------------------------------------------------------------- -->

<template>
	<page-meta :page-style="'overflow:' + (pageShow ? 'hidden' : 'visible')"></page-meta>
	<view class="container" :style="{'--theme-color': themeColor}" v-if="loadEnd">
		<!-- 用户信息 -->
		<view class="container-user flex align-items-center">
			<view class="user-bg"></view>
			<image class="user-avatar" src="/static/avatar.png" mode="aspectFill"></image>
			<view class="user-statistics flex-item flex align-items-center">
				<view class="statistics-box">
					<view class="title">今日接单</view>
					<view class="value">{{driverInfo.statistics.today_acceptance_number || 0}}</view>
				</view>
				<view class="statistics-box">
					<view class="title">今日收入(元)</view>
					<view class="value">{{driverInfo.statistics.today_income || 0}}</view>
				</view>
			</view>
			<view class="user-btn" :style="{'--btn-color': driverInfo.order_status == 1 ? '#F9602E' : themeColor}" @click="changeReceiving()">
				<view class="btn-bg"></view>
				<view class="btn-box" v-if="driverInfo.order_status == 1">休息</view>
				<view class="btn-box" v-else>开始接单</view>
			</view>
			<view class="user-notice flex align-items-center" v-if="showNewOrderTips" @click="resetOrderList()">
				<view class="notice-icon" :style="{'background-image': 'url('+ iconUpward +')'}" v-if="iconUpward"></view>
				<text class="notice-text">新订单</text>
			</view>
		</view>
		<!-- 订单列表 -->
		<view class="container-main">
			<view class="main-list" v-if="orderList.length">
				<order-list :show-data="orderList"></order-list>
			</view>
			<view class="main-empty" v-else>
				<image class="icon" src="/static/driver/empty.png" mode="heightFix"></image>
				<view class="text flex-column align-items-center">
					<text>暂无行程订单</text>
					<text v-if="driverInfo.order_status == 1">请耐心等待更多乘客发单</text>
					<text v-else>请开启【开始接单】进行接单</text>
				</view>
			</view>
		</view>
		<!-- 报单按钮 -->
		<view class="container-btn flex-column flex-center" @click="openCreateModal()" v-if="driverInfo.order_status == 1">
			<image class="btn-icon" src="/static/driver/code.png" mode="aspectFit"></image>
			<text class="btn-text">报单</text>
		</view>
		<!-- 底部导航 -->
		<tab-bar></tab-bar>
		<!-- 报单类型弹窗 -->
		<create-order-modal ref="createOrderModal" @onConfirm="onConfirmCreate" @onChange="pageChange"></create-order-modal>
		<!-- 报单二维码弹窗 -->
		<code-order-modal ref="codeOrderModal" :show-data="driverInfo.applet_driver_report_order_path" @onChange="pageChange"></code-order-modal>
	</view>
</template>

<script>
	import { mapState } from "vuex"
	import svgData from "@/common/svg.js"
	import orderList from "@/pages/driver/component/order/list.vue"
	import tabBar from "@/pages/component/tab-bar/tab-bar.vue"
	import createOrderModal from "@/pages/driver/component/modal/create-order.vue"
	import codeOrderModal from "@/pages/driver/component/modal/code-order.vue"
	import WebsocketUtil from '@/common/socket.js';
	export default {
		components: {
			orderList,
			tabBar,
			createOrderModal,
			codeOrderModal,
		},
		data() {
			return {
				// 加载完成
				loadEnd: false,
				// 页面是否阻止滚动
				pageShow: false,
				// 是否已经登录
				alreadyLogged: false,
				// 是否停止定位
				isStopLocation: false,
				// 司机信息
				driverInfo: {
					statistics: {
						today_acceptance_number: 0,
						today_income: 0,
					},
					order_status: 2,
				},
				// 订单列表
				orderList: [],
				// 分类查询参数
				page: 1,
				limit: 20,
				hasMore: false,
				// 当前定位信息
				currentLocation: null,
				// 已上传的定位信息
				uploadedLocation: null,
				// 定时更新位置定时器
				updateLocationTimer: null,
				// WebSocket 实例
				websocket: null,
				// 新订单通知监听状态 1.正在监听，2.未监听
				orderListenStatus: 2,
				// 通知音频播放状态 1.正在播放，2.未播放
				orderAudioStatus: 2,
				// 音频播放重置定时器
				orderAudioTimer: null,
				// 是否显示新订单提示
				showNewOrderTips: false,
			}
		},
		computed: {
			...mapState({
				themeColor: state => state.app.themeColor,
				websocketPort: state => state.app.websocketPort,
				newOrderNotice: state => state.app.newOrderNotice,
				shareTitle: state => state.app.shareTitle,
				shareImage: state => state.app.shareImage,
				iconUpward: state => {
					return svgData.svgToUrl("upward", state.app.themeColor)
				},
			})
		},
		async onLoad() {
			await this.$onLaunched
			this.getDriverInfo(() => {
				this.loadEnd = true
			})
		},
		onShow() {
			if (this.loadEnd) {
				uni.pageScrollTo({
					scrollTop: 0,
					duration: 0
				});
				this.page = 1
				if (!this.alreadyLogged && uni.getStorageSync("token")) {
					uni.showLoading({
						title: "加载中",
						mask: true,
					})
				}
				this.getDriverInfo(() => {
					uni.hideLoading()
				})
			}
		},
		onHide() {
			setTimeout(() => {
				let pages = getCurrentPages()
				if (pages.length && pages[pages.length - 1].route == "pages/driver/index/index") return
				if (this.websocket) {
					this.websocket.destroy();
					this.orderListenStatus = 2
					this.orderAudioStatus = 2
				}
				if (this.updateLocationTimer) clearInterval(this.updateLocationTimer)
			}, 500);
		},
		onUnload() {
			if (this.websocket) {
				this.websocket.destroy();
				this.orderListenStatus = 2
				this.orderAudioStatus = 2
			}
			if (this.updateLocationTimer) clearInterval(this.updateLocationTimer)
		},
		onPullDownRefresh() {
			this.page = 1
			this.getDriverInfo(() => {
				uni.stopPullDownRefresh()
			})
		},
		onReachBottom() {
			if (this.hasMore) {
				this.page++
				this.getOrderList()
			}
		},
		onShareAppMessage() {
			return {
				title: this.shareTitle,
				imageUrl: this.shareImage,
			}
		},
		onShareTimeline() {
			return {
				title: this.shareTitle,
				imageUrl: this.shareImage,
			}
		},
		methods: {
			// 改变页面滚动状态
			pageChange(state) {
				this.pageShow = state
			},
			// 切换接单状态
			async changeReceiving() {
				if (!this.$util.verifyLogin() || !this.driverInfo) return
				uni.showLoading({
					title: "加载中",
					mask: true
				})
				if (this.driverInfo.certification_examine_status != 2) {
					const authStatus = await this.getAuthStatus()
					if (!authStatus) {
						uni.hideLoading()
						uni.showModal({
							content: ' 请先进行实名认证后接单， \n 是否前往认证？ ',
							confirmText: "前往认证",
							confirmColor: this.themeColor,
							success: (res) => {
								if (res.confirm) {
									this.$util.toPage({
										mode: 1,
										path: "/pages/driver/mine/authentication/index"
									})
								}
							}
						})
						return
					}
				}
				const status = this.driverInfo.order_status == 2 ? 1 : 2
				this.getAuthSetting(status, () => {
					if (status == 1 && !this.currentLocation) {
						uni.hideLoading()
						return
					}
					this.$util.request("driver.driverCenter.operate", {
						order_status: status
					}).then(res => {
						if (res.code == 1) {
							this.driverInfo.order_status = status
							if (this.driverInfo.order_status == 1) {
								this.updateLocation()
								if (this.updateLocationTimer) clearInterval(this.updateLocationTimer)
								this.uploadedLocation = null
								this.updateLocationTimer = setInterval(() => {
									this.getLocation(() => this.updateLocation())
								}, 10000);
								if (this.orderListenStatus == 2) this.listenOrderStatus()
								this.page = 1
								this.getOrderList(() => uni.hideLoading())
							} else {
								uni.hideLoading()
								this.orderList = []
								this.page = 1
								this.hasMore = false
								this.currentLocation = null
								this.uploadedLocation = null
								if (this.updateLocationTimer) clearInterval(this.updateLocationTimer)
							}
						} else {
							uni.hideLoading()
							uni.showToast({
								title: res.msg,
								icon: 'none'
							})
						}
					}).catch(error => {
						console.error('切换接单状态 ', error)
					})
				})
			},
			// 获取司机信息
			getDriverInfo(fn) {
				if (!uni.getStorageSync("token")) {
					this.driverInfo = {
						statistics: {
							today_acceptance_number: 0,
							today_income: 0,
						},
						order_status: 2,
					}
					this.alreadyLogged = false
					this.orderList = []
					if (fn) fn()
					return
				}
				this.alreadyLogged = true
				this.$util.request("driver.driverCenter.info").then(res => {
					if (res.code == 1) {
						this.driverInfo = res.data
						const userInfo = uni.getStorageSync("userInfo") || {}
						userInfo.certification_examine_status = res.data.certification_examine_status
						this.$store.commit('user/setUserInfo', userInfo)
						this.getAuthSetting(this.driverInfo.order_status, () => {
							this.updateLocation()
							if (res.data.order_status == 1) {
								if (this.updateLocationTimer) clearInterval(this.updateLocationTimer)
								this.uploadedLocation = null
								this.updateLocationTimer = setInterval(() => {
									this.getLocation(() => this.updateLocation())
								}, 10000);
							}
							if (this.orderListenStatus == 2) this.listenOrderStatus()
							this.getOrderList(() => {
								if (fn) fn()
							})
						})
					} else {
						if (fn) fn()
						uni.showToast({
							title: res.msg,
							icon: 'none'
						})
					}
				}).catch(error => {
					if (fn) fn()
					console.error('获取司机信息 ', error)
				})
			},
			// 获取用户认证状态
			getAuthStatus() {
				return new Promise((resolve) => {
					this.$util.request("driver.user").then(res => {
						if (res.code == 1) {
							uni.setStorageSync("userInfo", res.data)
							this.$store.commit('user/setUserInfo', res.data)
							resolve(res.data.certification_examine_status == 2)
						} else {
							resolve(false)
						}
					}).catch(() => {
						resolve(false)
					})
				})
			},
			// 获取位置权限
			async getAuthSetting(status, fn) {
				if (status == 2 || this.isStopLocation) {
					if (fn) fn()
					return
				}
				try {
					const permissionStatus = await this.$util.checkLocationPermission()
					if (permissionStatus == 1) {
						this.getLocation(fn)
					} else {
						if (fn) fn()
						this.currentLocation = null
						if (permissionStatus == 2) this.isStopLocation = true
						this.$util.setLocationPermission(permissionStatus, (result) => {
							this.isStopLocation = false
							// #ifdef MP-WEIXIN 
							if (result) this.getLocation()
							// #endif
						})
					}
				} catch (error) {
					this.currentLocation = null
					if (fn) fn()
					uni.showToast({
						title: error.message,
						icon: 'none',
						duration: 2000,
					})
				}
			},
			// 获取当前位置坐标
			getLocation(fn) {
				uni.getLocation({
					type: 'gcj02',
					geocode: true,
					success: (res) => {
						this.currentLocation = {
							latitude: res.latitude,
							longitude: res.longitude,
						}
						if (fn) fn()
					},
					fail: () => {
						if (fn) fn()
						uni.showToast({
							title: '位置获取失败',
							icon: 'none',
							duration: 2000,
						})
					},
				})
			},
			// 更新司机位置
			updateLocation() {
				if (this.driverInfo.order_status == 2 || !this.currentLocation) return
				if (this.uploadedLocation && this.uploadedLocation.latitude && this.uploadedLocation.longitude) {
					const distance = this.getDistance(this.uploadedLocation, this.currentLocation)
					if (parseFloat(distance) < 2) return
				}
				this.$util.request("driver.driverCenter.update", {
					driver_lat: this.currentLocation.latitude,
					driver_lng: this.currentLocation.longitude,
				}).then(res => {
					if (res.code == 1) {
						this.uploadedLocation = this.currentLocation
					}
				}).catch(error => {
					console.error('获取司机信息 ', error)
				})
			},
			// 根据经纬度计算距离
			getDistance(location1, location2) {
				var lat1 = location1.latitude
				var lng1 = location1.longitude
				var lat2 = location2.latitude
				var lng2 = location2.longitude
				var radLat1 = lat1 * Math.PI / 180.0;
				var radLat2 = lat2 * Math.PI / 180.0;
				var a = radLat1 - radLat2;
				var b = lng1 * Math.PI / 180.0 - lng2 * Math.PI / 180.0;
				var s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
				s = s * 6378.137 * 1000;
				return parseFloat(s);
			},
			// 获取订单列表
			getOrderList(fn) {
				if (this.driverInfo.order_status == 2 || !this.currentLocation) {
					if (fn) fn()
					return
				}
				this.$util.request("driver.order.grabList", {
					page: this.page,
					limit: this.limit,
					lng: this.currentLocation.longitude,
					lat: this.currentLocation.latitude,
				}).then(res => {
					if (fn) fn()
					if (res.code == 1) {
						let list = res.data.data
						this.hasMore = this.page < res.data.total / this.limit ? true : false
						this.orderList = this.page == 1 ? list : [...this.orderList, ...list];
						if (this.page == 1 && this.showNewOrderTips) this.showNewOrderTips = false
					} else {
						uni.showToast({
							title: res.msg,
							icon: 'none'
						})
					}
				}).catch(error => {
					if (fn) fn()
					console.error('获取订单列表 ', error)
				})
			},
			// 重置订单列表
			resetOrderList() {
				uni.pageScrollTo({
					scrollTop: 0,
					duration: 0
				});
				this.page = 1
				this.getOrderList()
			},
			// 打开报单弹窗
			openCreateModal() {
				if (this.driverInfo.order_status != 1) {
					uni.showToast({
						icon: "none",
						title: "请开启【开始接单】后进行报单",
						duration: 2000
					})
					return
				}
				if (parseInt(this.driverInfo.driver_receive_count) > 0) {
					uni.showModal({
						content: " 您有正在进行中的订单， \n 请完成后再进行报单 ",
						showCancel: false,
						confirmColor: this.themeColor,
						confirmText: "我知道了",
					})
					return
				}
				this.$refs.createOrderModal.open()
			},
			// 确认报单类型
			onConfirmCreate(type) {
				if (type == 1) {
					this.$util.toPage({
						mode: 1,
						path: "/pages/driver/order/create"
					})
				} else {
					this.$refs.codeOrderModal.open()
				}
			},
			// 监听订单状态
			listenOrderStatus() {
				if (!uni.getStorageSync("token")) return
				if (this.driverInfo.order_status == 2 || !this.currentLocation) return
				if (!this.websocketPort) {
					setTimeout(() => {
						this.listenOrderStatus()
					}, 200);
					return
				}
				this.websocket = new WebsocketUtil('wss://' + this.websocketPort, 5);
				// 可以注册消息回调  
				this.websocket.onMessage(res => {
					if (res.type == "init") {
						this.$util.request("main.socket.bindChat", { client_id: res.client_id }).then(result => {
							if (result.code == 1) {
								this.orderListenStatus = 1
							} else {
								this.orderListenStatus = 2
							}
						}).catch(error => {
							console.error('绑定 ', error)
						})
					} else if (res.type == "newOrderMessage") {
						if (this.orderAudioStatus == 2) {
							this.orderAudioStatus = 1
							if (this.orderAudioTimer) clearTimeout(this.orderAudioTimer)
							this.orderAudioTimer = setTimeout(() => {
								this.orderAudioStatus = 2
							}, 5000);
							var soundAndVibrate = uni.getStorageSync("soundAndVibrate")
							if (!soundAndVibrate) {
								soundAndVibrate = {
									soundOpen: true,
									vibrateOpen: true,
								}
							}
							if (soundAndVibrate.vibrateOpen) uni.vibrateLong();
							if (soundAndVibrate.soundOpen) {
								const innerAudioContext = uni.createInnerAudioContext();
								innerAudioContext.autoplay = true;
								innerAudioContext.src = this.newOrderNotice;
								innerAudioContext.onEnded(() => {
									this.orderAudioStatus = 2
								});
							}
							uni.createSelectorQuery().in(this).select('.container-main').boundingClientRect(res => {
								try {
									if (res.top > 0) {
										this.resetOrderList()
									} else {
										this.showNewOrderTips = true
									}
								} catch (error) {
									this.resetOrderList()
								}
							}).exec();
						}
					} else if (res.type == "reportOrderMessage") {
						try {
							if (this.$refs?.codeOrderModal) this.$refs.codeOrderModal.onClose()
							this.$util.toPage({
								mode: 1,
								path: `/pages/driver/order/details?id=${res.id}`,
								isToken: true,
							})
						} catch (error) {
							this.$util.toPage({
								mode: 1,
								path: `/pages/driver/order/details?id=${res.id}`,
								isToken: true,
							})
						}
					}
				});
			},
		}
	}
</script>

<style lang="scss">
	.container {
		.container-user {
			position: sticky;
			top: 0;
			z-index: 99;
			padding: 24rpx 32rpx;
			background: #fff;

			.user-bg {
				position: absolute;
				top: 0;
				left: 0;
				right: 0;
				bottom: 0;
				z-index: -1;
				background: var(--theme-color);
				opacity: .05;
			}

			.user-avatar {
				width: 84rpx;
				height: 84rpx;
				min-width: 84rpx;
				border-radius: 50%;
			}

			.user-statistics {
				.statistics-box {
					margin-left: 44rpx;

					.title {
						color: #8D929C;
						font-size: 24rpx;
						line-height: 34rpx;
					}

					.value {
						margin-top: 16rpx;
						color: #242629;
						font-size: 32rpx;
						font-weight: 600;
						line-height: 44rpx;
					}
				}
			}

			.user-btn {
				position: relative;
				z-index: 1;
				padding: 4rpx;
				min-width: 160rpx;

				.btn-bg {
					position: absolute;
					z-index: -1;
					top: 0;
					left: 0;
					right: 0;
					bottom: 0;
					border-radius: 32rpx;
					background: var(--btn-color);
					opacity: .5;
				}

				.btn-box {
					color: #FFF;
					font-size: 28rpx;
					font-weight: 600;
					line-height: 40rpx;
					border-radius: 32rpx;
					background: var(--btn-color);
					padding: 20rpx;
					text-align: center;
				}
			}

			.user-notice {
				position: absolute;
				bottom: -16rpx;
				left: 50%;
				z-index: 9;
				transform: translate(-50%, 100%);
				background: #FFF;
				border-radius: 56rpx;
				padding: 12rpx 24rpx;
				border: 1rpx solid #eee;
				box-shadow: 0 0 20rpx 0 rgba(0, 0, 0, 0.10);

				.notice-icon {
					width: 32rpx;
					height: 32rpx;
					background-size: 32rpx;
				}

				.notice-text {
					margin-left: 8rpx;
					color: var(--theme-color);
					text-align: center;
					font-size: 24rpx;
					font-weight: 600;
					line-height: 32rpx;
				}
			}
		}

		.container-main {
			overflow: hidden;
			position: relative;

			.main-list {
				padding: 32rpx;
			}

			.main-empty {
				padding-top: 18vh;

				.icon {
					height: 300rpx;
					margin: 0 auto;
				}

				.text {
					margin-top: 16rpx;
					color: #242629;
					text-align: center;
					font-size: 28rpx;
					font-weight: 600;
					line-height: 40rpx;
				}
			}
		}

		.container-btn {
			position: fixed;
			right: 32rpx;
			bottom: 248rpx;
			z-index: 98;
			background: var(--theme-color);
			border-radius: 32rpx;
			width: 112rpx;
			height: 112rpx;

			.btn-icon {
				width: 48rpx;
				height: 48rpx;
			}

			.btn-text {
				color: #FFF;
				text-align: center;
				font-size: 24rpx;
				font-weight: 600;
				line-height: 34rpx;
			}
		}
	}
</style>